package com.xinzhitong.www.config;

import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro配置类
 *
 * @author 徐鑫
 */
@Configuration
@EnableCaching
public class ShiroConfiguration {

    /**
     * 返回一个缓存器
     *
     * @return 缓存器
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public EhCacheManager ehCacheManager() {
        System.out.println("ShiroConfiguration.getEhCacheManager()");
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:ehcache-setting.xml");
        return cacheManager;
    }

    /**
     * 开启Shiro注解(如@RequiresRoles,@RequiresPermissions),
     * 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)
     */
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启aop注解支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.web.mgt.DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    //权限管理，配置主要是Realm的管理认证
    @Bean
    public org.apache.shiro.web.mgt.DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    //Filter工厂，设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.web.mgt.DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new LinkedHashMap<>();
        //静态资源与游客资源不设防
        map.put("/system/getAboutUs", "anon");
        map.put("/system/getContactUs", "anon");
        map.put("/system/getServiceAgreement", "anon");
        map.put("/static/**", "anon");
        map.put("/user/loginTry", "anon");
        map.put("/user/SMSCode", "anon");
        map.put("/user/registerByPhone", "anon");
        map.put("/user/email", "anon");
        map.put("/user/emailAccountActive", "anon");
        map.put("/user/emailAccountPasswordReset", "anon");
        map.put("/user/resetPassword", "anon");
        map.put("/visitor/**", "anon");
        map.put("/visitor/getProfessionInformation", "anon");
        map.put("/course/general", "anon");
        map.put("/pay/pay", "anon");
        map.put("/consign/consignSatisfyTheConditionsOf", "anon");
        map.put("/train/getTrainOutline", "anon");
        map.put("/post/postsSatisfyTheConditionsOf", "anon");
        map.put("/company/companiesView", "anon");
        //登出
        map.put("/logout", "logout");
        //对所有用户认证
        map.put("/**", "authc");
        //配置 记住密码 的账户 可直接访问的页面
        map.put("/index", "user");
        map.put("/hello", "user");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        //登录
        shiroFilterFactoryBean.setLoginUrl("/user/login");
        //首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //错误页面，认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");

        return shiroFilterFactoryBean;
    }

    /**
     * 返回一个自定义的ShiroRealm
     *
     * @return 自定义的ShiroRealm
     */
    @Bean
    public MyShiroRealm myShiroRealm() {
        return new MyShiroRealm(retryLimitCredentialsMatcher());
    }

    /**
     * 返回一个密码验证器
     *
     * @return 密码验证器
     */
    @Bean(name = "CredentialsMatcher")
    public CredentialsMatcher retryLimitCredentialsMatcher() {
        RetryLimitCredentialsMatcher retryLimitCredentialsMatcher =
                new RetryLimitCredentialsMatcher(ehCacheManager(), "Here!!!!");
        retryLimitCredentialsMatcher.setMaxRetryCount();
        return retryLimitCredentialsMatcher;
    }

    /**
     * 管理缓存管理器的生存周期
     *
     * @return 缓存管理器进程管理器
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 返回一个简单cookie模板
     *
     * @return cookie模板
     */
    @Bean
    public SimpleCookie rememberMeCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("rememberMeFromENV");
        simpleCookie.setMaxAge(20 * 24 * 60 * 60);
        return simpleCookie;
    }

    /**
     * 根据作用域中的cookie模板生成cookie管理器
     *
     * @return cookie管理器
     */
    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
        return cookieRememberMeManager;
    }

}
